package com.weixin.project.Service;

import com.weixin.project.Dao.FavoriteDao;
import com.weixin.project.Entity.Favorite;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;

import java.net.InetAddress;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
public class FavoriteService {
    @Value("10")
    Integer pageSize;
    @Autowired
    FavoriteDao favoriteDao;
    @Autowired
    RedisTemplate redisTemplate;
    //entity
    private final static String FAVORITE = "favorite";
    //zset，key为questionId，score为时间戳
    private final static String FAVORITES_OF_USER_ZSET = "favorites_of_user";
    @CachePut(value = FAVORITE, key = "#favorite.userId + '::' + #favorite.questionId", unless = "#result == null ")
    public Favorite storeFavorite(Favorite favorite) {
        String zsetKey = FAVORITES_OF_USER_ZSET + "::" + favorite.getUserId();
        String key = "key::" + favorite.getQuestionId();
        if (!redisTemplate.hasKey(zsetKey)) loadUserFavorite2Redis(favorite.getUserId());
        redisTemplate.boundZSetOps(zsetKey).add(key, favorite.getCreateTime().getTime());
        return favoriteDao.save(favorite);
    }

    @CacheEvict(value = FAVORITE, key = "#favorite.userId + '::' + #favorite.questionId")
    public void deleteFavorite(Favorite favorite) {
        String zsetKey = FAVORITES_OF_USER_ZSET + "::" + favorite.getUserId();
        String key = "key::" + favorite.getQuestionId();
        redisTemplate.boundZSetOps(zsetKey).remove(key);
        favoriteDao.delete(favorite);
    }

    @Cacheable(value = FAVORITE, key = "#userId + '::' + #questionId", unless = "#result == null")
    public Favorite findFavorite(Integer questionId, Integer userId){
        return favoriteDao.getFavoriteByQuestionIdAndUserId(questionId, userId);
    }

    public List<Favorite> findUserFavorites(Integer userId, Integer page){
        String zsetKey = FAVORITES_OF_USER_ZSET + "::" + userId;
        if (!redisTemplate.hasKey(zsetKey)){
            loadUserFavorite2Redis(userId);
        }
        Set<ZSetOperations.TypedTuple> tupleSet = redisTemplate.boundZSetOps(zsetKey).rangeWithScores(0, -1);
        List<ZSetOperations.TypedTuple> tupleList = tupleSet.stream().
                sorted((p2, p1) -> p1.getScore().compareTo(p2.getScore())).collect(Collectors.toList());
        tupleList.subList(page * pageSize, Math.min(tupleList.size(), (page + 1) * pageSize));
        return tupleList.stream().map(x ->
                findFavorite(Integer.parseInt(x.getValue().toString().split("::")[1]), userId)).
                collect(Collectors.toList());
    }

    public Integer countTotalPagesOfUserFavorite(Integer userId){
        String zsetKey = FAVORITES_OF_USER_ZSET + "::" + userId;
        if (!redisTemplate.hasKey(zsetKey)) loadUserFavorite2Redis(userId);
        Integer size = redisTemplate.boundZSetOps(zsetKey).size().intValue();
        return size%10 == 0 ? size/pageSize : size/pageSize + 1;
    }

    public Integer countAllFavoritesOfUser(Integer userId){
        String zsetKey = FAVORITES_OF_USER_ZSET + "::" + userId;
        if (!redisTemplate.hasKey(zsetKey)) loadUserFavorite2Redis(userId);
        return redisTemplate.hasKey(zsetKey)?redisTemplate.boundZSetOps(zsetKey).size().intValue():0;
    }

    /**
     * 将用户的收藏数据从mysql缓存到redis中
     * @param userId 用户id
     */
    public void loadUserFavorite2Redis(Integer userId){
        String zsetKey = FAVORITES_OF_USER_ZSET + "::" + userId;
        if (redisTemplate.hasKey(zsetKey)) return;
        List<Favorite> favorites = favoriteDao.getFavoritesByUserId(userId);
        for (Favorite favorite:favorites){
            String key = "key::" + favorite.getQuestionId();
            redisTemplate.boundZSetOps(zsetKey).add(key, favorite.getCreateTime().getTime());
        }
        redisTemplate.expire(zsetKey, 180, TimeUnit.MINUTES);
    }
}
